package com.ciei.dpagm.service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ciei.dpagm.common.enums.FormValueTypeEnum;
import com.ciei.dpagm.common.service.BaseService;
import com.ciei.dpagm.entity.FormProperty;
import com.ciei.dpagm.entity.FormPropertyDefinition;
import com.ciei.dpagm.mapper.FormPropertyMapper;
import com.ciei.dpagm.util.APP;
import com.ciei.dpagm.util.JsonUtil;
import com.ciei.dpagm.util.StringUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author wangyan
 * @date 2021/06/01
 */
@Service
public class FormPropertyService extends BaseService<FormPropertyMapper, FormProperty> {

    @Lazy
    @Autowired
    private FormPropertyDefinitionService formPropertyDefinitionService;


    /**
     * 根据业务模块,类别和businessKey匹配对应的属性
     * @param query
     * @return
     */
    public JSONObject matchSingleInstanceWithProperties(JSONObject query){
        JSONArray propertyArray = new JSONArray();
        Integer businessModule = query.getInteger("businessModule");
        Integer classificationId = query.getInteger("classificationId");
        String businessKey = query.getString("businessKey");
        if (businessModule == null || classificationId == null || StringUtil.isNullOrEmpty(businessKey)){
            return JsonUtil.getSuccess("").fluentPut(APP.DATA, propertyArray);
        }
        List<FormProperty> formPropertyList = findByProperties(new String[]{"businessModule","classificationId","businessKey"},new Object[]{businessModule,classificationId,businessKey});
        if (formPropertyList.isEmpty()){
            return JsonUtil.getSuccess("").fluentPut(APP.DATA, propertyArray);
        }
        List<Integer> propertyDefinitionIds = formPropertyList.stream().map(FormProperty::getPropertyDefinitionId).collect(Collectors.toList());
        LambdaQueryWrapper<FormPropertyDefinition> definitionLambdaQueryWrapper = new LambdaQueryWrapper<>();
        definitionLambdaQueryWrapper.in(FormPropertyDefinition::getPropertyDefinitionId,propertyDefinitionIds);
        List<FormPropertyDefinition> definitionList = formPropertyDefinitionService.list(definitionLambdaQueryWrapper);
        for (FormProperty formProperty : formPropertyList){
            FormPropertyDefinition definition = definitionList.stream().filter(d->d.getPropertyDefinitionId().equals(formProperty.getPropertyDefinitionId())).findFirst().orElse(null);
            if (definition!=null){
                String propertyValue = formProperty.getPropertyValue();
                JSONObject propertyData = new JSONObject();
                propertyData.put("propertyKey",definition.getPropertyKey());
                if (StringUtils.isNotBlank(propertyValue)){
                    putPropertyValue(definition.getValueType(),propertyValue,propertyData);
                }
                propertyArray.add(propertyData);
            }
        }
        return JsonUtil.getSuccess("").fluentPut(APP.DATA, propertyArray);
    }

    /**
     * 查询表单属性列表
     * @param businessModule
     * @param classificationIds
     * @return
     */
    public List<JSONObject> matchMultipleInstance(Integer businessModule, Set<Integer> classificationIds){
        List<JSONObject> formPropertyList = new ArrayList<>();
        if (!classificationIds.isEmpty()){
            LambdaQueryWrapper<FormProperty> propertyLambdaQueryWrapper = new LambdaQueryWrapper<>();
            propertyLambdaQueryWrapper.eq(FormProperty::getBusinessModule,businessModule);
            propertyLambdaQueryWrapper.in(FormProperty::getClassificationId,classificationIds);
            List<FormProperty> propertyList = list(propertyLambdaQueryWrapper);
            if (!propertyList.isEmpty()){
                List<Integer> propertyDefinitionIds = propertyList.stream().map(FormProperty::getPropertyDefinitionId).collect(Collectors.toList());
                LambdaQueryWrapper<FormPropertyDefinition> definitionLambdaQueryWrapper = new LambdaQueryWrapper<>();
                definitionLambdaQueryWrapper.in(FormPropertyDefinition::getPropertyDefinitionId,propertyDefinitionIds);
                List<FormPropertyDefinition> definitionList = formPropertyDefinitionService.list(definitionLambdaQueryWrapper);
                for (FormProperty formProperty : propertyList){
                    FormPropertyDefinition definition = definitionList.stream().filter(d->d.getPropertyDefinitionId().equals(formProperty.getPropertyDefinitionId())).findFirst().orElse(null);
                    if (definition!=null){
                        JSONObject propertyData = new JSONObject();
                        propertyData.put("businessKey",formProperty.getBusinessKey());
                        propertyData.put("propertyKey",definition.getPropertyKey());
                        propertyData.put("valueType",definition.getValueType());
                        propertyData.put("propertyValue",formProperty.getPropertyValue());
                        propertyData.put("classificationId",formProperty.getClassificationId());
                        formPropertyList.add(propertyData);
                    }
                }
            }
        }
        return formPropertyList;
    }

    /**
     * 根据业务模块,类别和businessKey匹配对应的属性
     * @param businessModule
     * @param classificationId
     * @param businessKey
     * @return
     */
    public Map<String,String>  matchSingleInstanceWithProperties(Integer businessModule,Integer classificationId,String businessKey){
        Map<String,String> propertyMap = new HashMap<>();
        List<FormProperty> formPropertyList = findByProperties(new String[]{"businessModule","classificationId","businessKey"},new Object[]{businessModule,classificationId,businessKey});
        if (!formPropertyList.isEmpty()){
            List<Integer> propertyDefinitionIds = formPropertyList.stream().map(FormProperty::getPropertyDefinitionId).collect(Collectors.toList());
            LambdaQueryWrapper<FormPropertyDefinition> definitionLambdaQueryWrapper = new LambdaQueryWrapper<>();
            definitionLambdaQueryWrapper.in(FormPropertyDefinition::getPropertyDefinitionId,propertyDefinitionIds);
            List<FormPropertyDefinition> definitionList = formPropertyDefinitionService.list(definitionLambdaQueryWrapper);
            for (FormProperty formProperty : formPropertyList){
                FormPropertyDefinition definition = definitionList.stream().filter(d->d.getPropertyDefinitionId().equals(formProperty.getPropertyDefinitionId())).findFirst().orElse(null);
                if (definition!=null){
                    propertyMap.put(definition.getPropertyKey(),formProperty.getPropertyValue());
                }
            }
        }
        return propertyMap;
    }


    /**
     * 增加或修改表单属性
     * @param properties
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public JSONObject saveOrUpdateFormProperty(JSONArray properties,String businessKey,Integer classificationId,Integer businessModule){
        //需要删除的属性
        List<Integer> deletePropertyIdList = new ArrayList<>();
        List<FormProperty> oldPropertyList = findByProperties(new String[]{"businessKey", "businessModule"}, new Object[]{businessKey, businessModule});
        //类别是否有变动
        Boolean isChangedOfClassificationId = false;
        if (classificationId != null && !oldPropertyList.isEmpty() && properties != null && !properties.isEmpty()){
            List<FormProperty> tempList = oldPropertyList.stream().filter(o ->o.getClassificationId().equals(classificationId)).collect(Collectors.toList());
            //类别有变动,需删除老的类别的数据
            if (tempList.isEmpty()){
                isChangedOfClassificationId = true;
                deletePropertyIdList.addAll(oldPropertyList.stream().map(FormProperty::getPropertyId).collect(Collectors.toList()));
            }
        }
        if (properties != null && !properties.isEmpty()) {
            List<FormPropertyDefinition> definitionList = formPropertyDefinitionService.findByProperties(new String[]{"businessModule"},new Integer[]{businessModule});
            List<Integer> oldPropertyDefinitionIds = oldPropertyList.stream().map(FormProperty::getPropertyDefinitionId).collect(Collectors.toList());
            //需要新增的属性
            List<FormProperty> insertList = new ArrayList<>();
            //需要修改的属性
            List<FormProperty> updateList = new ArrayList<>();
            for (int i = 0; i < properties.size(); i++) {
                JSONObject property = properties.getJSONObject(i);
                String propertyKey = property.getString("propertyKey");
                FormPropertyDefinition definition = definitionList.stream().filter(d ->d.getPropertyKey().equals(propertyKey)).findFirst().orElse(null);
                if (definition !=null){
                    FormProperty formProperty = new FormProperty();
                    if (FormValueTypeEnum.ARRAY.getTypeId().equals(definition.getValueType())){
                        formProperty.setPropertyValue(StringUtils.join(property.getJSONArray("propertyValue"),","));
                    }else {
                        formProperty.setPropertyValue(property.getString("propertyValue"));
                    }
                    Integer propertyDefinitionId = definition.getPropertyDefinitionId();
                    if (!isChangedOfClassificationId && oldPropertyDefinitionIds.contains(propertyDefinitionId)){
                        FormProperty oldFormProperty = oldPropertyList.stream().filter(o ->o.getPropertyDefinitionId().equals(propertyDefinitionId)).findFirst().orElse(null);
                        Integer oldPropertyId = oldFormProperty.getPropertyId();
                        formProperty.setPropertyId(oldPropertyId);
                        updateList.add(formProperty);
                        oldPropertyDefinitionIds.remove(propertyDefinitionId);
                    }else {
                        formProperty.setBusinessKey(businessKey);
                        formProperty.setPropertyDefinitionId(propertyDefinitionId);
                        formProperty.setBusinessModule(businessModule);
                        formProperty.setClassificationId(classificationId);
                        insertList.add(formProperty);
                    }
                }
            }
            if (!insertList.isEmpty()) {
                saveBatch(insertList);
            }
            if (!updateList.isEmpty()) {
                updateBatchById(updateList);
            }
            if (!oldPropertyDefinitionIds.isEmpty()){
                oldPropertyList = oldPropertyList.stream().filter(o ->oldPropertyDefinitionIds.contains(o.getPropertyDefinitionId())).collect(Collectors.toList());
                deletePropertyIdList.addAll(oldPropertyList.stream().map(FormProperty::getPropertyId).collect(Collectors.toList()));
            }
        }else {
            if (!oldPropertyList.isEmpty()){
                deletePropertyIdList.addAll(oldPropertyList.stream().map(FormProperty::getPropertyId).collect(Collectors.toList()));
            }
        }

        if (!deletePropertyIdList.isEmpty()){
            deleteBatchByIds(deletePropertyIdList);
        }
        return JsonUtil.getSuccess("");
    }

    /**
     * 批量增加或修改表单属性
     * @param propertyList
     * @param businessKeyList
     * @param classificationIdList
     * @param businessModule
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    public JSONObject batchSaveOrUpdateFormProperty(List<JSONArray> propertyList,List<String> businessKeyList,List<Integer> classificationIdList,Integer businessModule){
        for (int i = 0; i < businessKeyList.size(); i++) {
            saveOrUpdateFormProperty(propertyList.get(i),businessKeyList.get(i),classificationIdList.get(i),businessModule);
        }
        return JsonUtil.getSuccess("");
    }

    /**
     * 批量删除
     * @param businessKeys
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatchByBusinessKeys(List<String> businessKeys, Integer businessModule){
        if (!businessKeys.isEmpty()){
            LambdaQueryWrapper<FormProperty> removeWrapper = new LambdaQueryWrapper<>();
            removeWrapper.eq(FormProperty::getBusinessModule,businessModule);
            removeWrapper.in(FormProperty::getBusinessKey,businessKeys);
            remove(removeWrapper);
        }
    }

    /**
     * 批量删除
     * @param definitionIds
     */
    @Transactional(rollbackFor = Exception.class)
    public void deleteBatchByDefinitionIds(List<Integer> definitionIds, Integer businessModule,Integer classificationId){
        if (!definitionIds.isEmpty()){
            LambdaQueryWrapper<FormProperty> removeWrapper = new LambdaQueryWrapper<>();
            removeWrapper.eq(FormProperty::getBusinessModule,businessModule);
            removeWrapper.eq(FormProperty::getClassificationId,classificationId);
            removeWrapper.in(FormProperty::getPropertyDefinitionId,definitionIds);
            remove(removeWrapper);
        }
    }

    /**
     * 获取表单属性列表
     * @return
     */
    public List<FormProperty> getFormPropertyList(Integer businessModule, Integer classificationId, Collection<?> businessKeyList){
        LambdaQueryWrapper<FormProperty> formPropertyLambdaQueryWrapper = new LambdaQueryWrapper<>();
        formPropertyLambdaQueryWrapper.eq(FormProperty::getBusinessModule,businessModule)
                .eq(FormProperty::getClassificationId,classificationId)
                .in(FormProperty::getBusinessKey,businessKeyList);
        return list(formPropertyLambdaQueryWrapper);
    }

    /**
     * 根据数据类型,保存真实类型值
     * @param valueType
     * @param propertyValue
     * @param propertyData
     */
    public void putPropertyValue(Integer valueType,String propertyValue,JSONObject propertyData){
        switch (FormValueTypeEnum.getEnumByValue(valueType)) {
            case STRING:
                propertyData.put("propertyValue", propertyValue);
                break;
            case NUMERIC:
                propertyData.put("propertyValue", Double.parseDouble(propertyValue));
                break;
            case ARRAY:
                propertyData.put("propertyValue", propertyValue.split(","));
                break;
            case BOOLEAN:
                propertyData.put("propertyValue", Boolean.parseBoolean(propertyValue));
                break;
            default:break;
        }
    }

    /**
     * 属性List转JSONArray
     * @param propertyList
     * @return
     */
    public JSONArray propertyListToArray(List<JSONObject> propertyList){
        JSONArray propertyArray = new JSONArray();
        for (JSONObject property : propertyList){
            JSONObject propertyData = new JSONObject();
            propertyData.put("propertyKey",property.getString("propertyKey"));
            putPropertyValue(property.getInteger("valueType"),property.getString("propertyValue"),propertyData);
            propertyArray.add(propertyData);
        }
        return propertyArray;
    }
}
